// Sculpture.cpp
#include "Sculpture.h"
#include <GL/gl.h>
#include <GL/glu.h>

//#include "GL/glu.h"

#include <fstream>
#include <string>
#include <stglut.h>
#define PI 3.14159265
#define VELOCITY 2000
#define ARROW_SIZE 100
#define TIME_PER_CURVE 2 //2 seconds per curve
#define RADIUS 100
#define CAM_INTERVAL 30
using namespace std;

float getDistance(vector<float> a, vector<float> b)
{
    return sqrt(pow(a[0]-b[0], 2) + pow(a[1]-b[1], 2) + pow(a[2]-b[2], 2));
}

vector<float> normalize(float x, float y, float z)
{
    float len = sqrt(pow(x,2) + pow(y,2) + pow(z,2));
    vector<float> rval(3);
    rval[0] = x/len;
    rval[1] = y/len;
    rval[2] = z/len;
    return rval;
}

vector<float> crossp(vector<float>a, vector<float>b)
{
    vector<float> rval(3);
    rval[0] = a[1]*b[2] - a[2]*b[1];
    rval[1] = a[2]*b[0] - a[0]*b[2];
    rval[2] = a[0]*b[1] - a[1]*b[0];
    return rval;
}

float dotp(vector<float>a, vector<float> b)
{
    return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
}
float toRadians(float degree)
{
    return degree*PI/180.;
}

float toDegrees(float radians)
{
    return radians*180./PI;
}

/*both pos and tan must be normalized */
void renderRing(vector<float> pos, vector<float> tan, float radius)
{
    glPushMatrix();
    vector<float> a(3);
    a[0] = 0.;
    a[1] = 0.;
    a[2] = 1.;

    vector<float> rvector = crossp(a,tan);
    glTranslatef(pos[0],pos[1],pos[2]);
    float rang = toDegrees(acos(dotp(a,tan)));
    glRotatef(rang, rvector[0], rvector[1], rvector[2]);

    float inc = 20;
    float ang = 0;
    float delta = 2*PI/inc;
    float px, py;
    glBegin(GL_LINE_STRIP);
    for (int a = 0; a < inc +1; a++)
    {
        px = radius*cos(ang);
        py = radius*sin(ang);
        glVertex3f(px,py,0.);
        ang += delta;
    }
    glEnd();
    glPopMatrix();
}

void tokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ")
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

void setColor(int z)
{
    float percent = (z+2.)/1284.;
    if (percent < .1)
    {
        percent*=10;
        glColor3f(0.,percent,1-percent);
    }
    else
    {
        percent= percent*1.111 - .111;
        glColor3f(percent,1-percent,0.);
    }
}

void Sculpture::SetState(TourDirection td)
{
    fprintf(stderr, "setstate td: %d. forward: %d backward: %d\n", td, D_FORWARD, D_BACKWARD);
    mDir = td;
    fprintf(stderr, "setstate mDir: %d\n", mDir);
}

void Sculpture::SetWindow1(int win)
{
    mWin1 = win;
}

void Sculpture::SetWindow2(int win)
{
    mWin2 = win;
}
void Sculpture::SetRingRadius(float rad)
{
    mRingRadius = rad;
}

void Sculpture::SetFree()
{
    mFree = 1;
}

void Sculpture::SetFPP()
{
    mFPP = 1;
}

void Sculpture::SetCFile(char * cfile)
{
    mCFile = cfile;
}

char * Sculpture::GetCFile()
{
    return mCFile;
}

void Sculpture::SetSFile(char * sfile)
{
    mSFile = sfile;
}

void Sculpture::SetVFile(char * vfile)
{
    mVFile = vfile;
}

void Sculpture::SetTFile(char *tfile)
{
    mTFile = tfile;
}
int Sculpture::GetFree()
{
    return mFree;
}

void Sculpture::parseLine(string line)
{
    /*Tokenize string*/
    vector<string>tokens;
    tokenize(line, tokens);
    if (tokens.size() == 3)
    {
        //Format: "edge 123 124"
        vector<int> edge(2);
        edge[0] = atoi(tokens[1].c_str());
        edge[1] = atoi(tokens[2].c_str());
        edges.push_back(edge);
    }
    else if (tokens.size() == 5)
    {
        //Format: "site 355 -153 406 123"
        vector<int> site(3);
        site[0] = atoi(tokens[1].c_str());
        site[1] = atoi(tokens[2].c_str());
        site[2] = atoi(tokens[3].c_str());
        sites.push_back(site);
    }
    else
    {
       // fprintf(stderr, "Skipping sites line: %s\n", line.c_str());
    }
}

void Sculpture::parseTourLine(string line)
{
    /*Tokenize string*/
    vector<string> tokens;
    tokenize(line, tokens);
    if (tokens.size() == 3) {
        //Format: "-3603 4592 6.1"
        vector<float> tour_site(3);
        tour_site[0] = atof(tokens[0].c_str());
        tour_site[1] = atof(tokens[1].c_str());
        tour_site[2] = atof(tokens[2].c_str());
        tour_sites.push_back(tour_site);
    }
    else {
        fprintf(stderr, "Skipping tour line: %s\n", line.c_str());
    }
}

void Sculpture::parseControlLine(string line)
{
    /*Tokenize string*/
    vector<string> tokens;
    tokenize(line, tokens, "\t");
    if (tokens.size() == 3) {
        //Format: "-3603 4592 6.1"
        vector<float> ctrl(3);
        ctrl[0] = atof(tokens[0].c_str());
        ctrl[1] = atof(tokens[1].c_str());
        ctrl[2] = atof(tokens[2].c_str());
        ctrls.push_back(ctrl);
    }
    else {
        fprintf(stderr, "Skipping control line: %s\n", line.c_str());
    }
}

void Sculpture::parseTriLine(string line)
{
	/*Tokenize string*/
    vector<string> tokens;
    tokenize(line, tokens, "\t");
    if (tokens.size() == 3) {
        //Format: "-3603 4592 6.1"
        vector<int> tri(3);
        //subtract one since MATLAB indices start from 1
        /*tri[0] = atoi(tokens[0].c_str()) -1;
        tri[1] = atoi(tokens[1].c_str()) -1;
        tri[2] = atoi(tokens[2].c_str()) -1;*/
        //Non-matlab version
                tri[0] = atoi(tokens[0].c_str());
        tri[1] = atoi(tokens[1].c_str());
        tri[2] = atoi(tokens[2].c_str());
        //fprintf(stderr, "Inserting %d %d %d\n", tri[0], tri[1],tri[2]);
        triangles.push_back(tri);
    }
    else {
        fprintf(stderr, "Skipping tri line: %s\n, tokenssize: %d", line.c_str(), tokens.size());
    }
}

void Sculpture::TourSetup()
{
    tour_sites.clear();
    ctrls.clear();
    ReadTourInfo();
    mVelocity = VELOCITY;
    mCTS = 0;
    mCTSST = 0.;
	mCPO = 0;
    mCurrentCurveD = getDistance(ctrls[0], ctrls[2]);
	//mCPST = 0.;
	mCurrentTime = 0.;
    mParamT = 0.;
	
}

void Sculpture::PrintInitialStats()
{
    /* min max of x, y, z */
    int minX, minY, minZ, maxX, maxY, maxZ;
    minX = maxX = sites[0][0];
    minY = maxY = sites[0][1];
    minZ = maxZ = sites[0][2];
    vector<int> csite(3);
    for (int a = 1; a < sites.size(); a++)
    {
        csite = sites[a];
        if (csite[0] < minX)
            minX = csite[0];
        else if (csite[0] > maxX)
            maxX = csite[0];
        if (csite[1] < minY)
            minY = csite[1];
        else if (csite[1] > maxY)
            maxY = csite[1];
        if (csite[2] < minZ)
            minZ = csite[2];
        else if (csite[2] > maxZ)
            maxZ = csite[2];
    }
    fprintf(stderr, "minX: %d maxX: %d minY: %d maxY: %d minZ: %d maxZ: %d\n", minX, maxX, minY, maxY, minZ, maxZ);
/*
    for (int a = 0; a < tours.size(); a++)
    {
        TourInfo tour = tours[a];
        fprintf(stderr, "tour %d distance: %f\n", a, tour.distance);
    }*/
}

void Sculpture::PrintCurrentStats()
{
    fprintf(stderr, "Position: x: %f y: %f z: %f\n", mCamTrans[0], mCamTrans[1], mCamTrans[2]);
    fprintf(stderr, "Angle: pitch %f, yaw: %f\n", mPitch, mYaw);
}

void Sculpture::ReadTourInfo() {
    ifstream stream;
    string line;
    // Now read the tour sites file
    if (mSFile == NULL)
        mSFile = "hw4.tour";
    stream.open(mSFile);
    if (!stream.is_open()) {
        fprintf(stderr, "Failed to open %s\n", mSFile);
        exit(1);
    }

    while (!stream.eof()) {
        getline(stream, line);
        parseTourLine( line);
        //printf("%s\n",line.c_str());
    }
    stream.close();

    //Read the bezier control points file
    if (mCFile == NULL)
        mCFile = "hw4.sequence16";
    stream.open(mCFile);
    if (!stream.is_open()) {
        fprintf(stderr, "Failed to open %s\n", mCFile);
        exit(1);
    }

    while (!stream.eof()) {
        getline(stream, line);
        parseControlLine( line);
        //printf("%s\n",line.c_str());
    }
    stream.close();
}

void Sculpture::ReadMap()
{
    if (mVFile == NULL) mVFile = "initial.edges";
    string line;
    ifstream stream;
    fprintf(stderr, "vfile is: %s\n",mVFile);
    stream.open(mVFile);
    if (!stream.is_open())
    {
        fprintf(stderr,"Failed to open %s\n", mVFile);
        exit(1);
    }

    while (! stream.eof())
    {
        getline(stream,line);
        parseLine(line);
        //printf("%s\n",line.c_str());
    } 
    stream.close();
	
	if (mTFile == NULL) mTFile = "hw4.triangles.txt.2";
    stream.open(mTFile);
	if (!stream.is_open())
	{
		fprintf(stderr,"Failed to open %s\n", mTFile);
		exit(1);
	}
	
	while (! stream.eof())
	{
		getline(stream,line);
		parseTriLine(line);
		//printf("%s\n",line.c_str());
	}
	stream.close();

}

/**
 * Animation parameters are updated here. Right now, it is just updating 
 * the current frame in the animation
 */

void Sculpture::Update(float CurrentTimeInSeconds)
{
    //fprintf(stderr, "begin mParamT: %f\n", mParamT);
    //fprintf(stderr, "State : %d\n", mDir);
    if (mDir == D_STOP)
    {
        //fprintf(stderr, "stopping\n");
        mCurrentTime = CurrentTimeInSeconds; //Just update the current time;
        return;
    }

    if (mFree || mCTS == tour_sites.size() - 1)
            return;
    // how much time has passed since last update?
    float dT = CurrentTimeInSeconds - mCurrentTime;

    if (mDir == D_FORWARD)
    {
        mParamT += dT;
    }

    if (mDir == D_BACKWARD)
    {
        mParamT -= dT;
    }

	mCurrentTime = CurrentTimeInSeconds;
	//float elapsed = mCurrentTime - mCPST;

	;
    //float t = mParamT/TIME_PER_CURVE;
    /* mParamT is some time. But t needs to be between 0 and 1. */
    float t = mParamT/(mCurrentCurveD/VELOCITY);
    //fprintf(stderr, "mParamT: %f t: %f\n", mParamT, t);
	
    if (t > 1.0f) // Reached end of the current set of ctrl points
    {
		//time to move on to the next tour site
		if (fabs(ctrls[mCPO+2][0] - tour_sites[mCTS+1][0]) < 10. && 
			fabs(ctrls[mCPO+2][1] - tour_sites[mCTS+1][1]) < 10. &&
			fabs(ctrls[mCPO+2][2] - tour_sites[mCTS+1][2]) < 10.)
		{
			fprintf(stderr,"reached site: %f %f %f\n", tour_sites[mCTS+1][0], tour_sites[mCTS+1][1], tour_sites[mCTS+1][2]);
             mCTS++;
             mCTSST = mCurrentTime;
		}
		//fprintf(stderr,"reached control point %f %f %f\n", ctrls[mCPO+2][0], ctrls[mCPO+2][1], ctrls[mCPO+2][2]); 
		
        mParamT = 0.;
		
		mCPO+=2;
        
        if ((mCPO +2) < ctrls.size())
        {
            mCurrentCurveD = getDistance(ctrls[mCPO], ctrls[mCPO+2]);
        }
       /* mParamT = (t - 1.0)*(mCurrentCurveD/VELOCITY);*/
        return;
    }
    if (t < 0.f) //Reached beginning of the curve.
    {
        fprintf(stderr, "mCPO: %d\n", mCPO);
        if (mCPO > 0)  // can move back another step
        {
            if (fabs(ctrls[mCPO+2][0] - tour_sites[mCTS+1][0]) < 5. &&
                        fabs(ctrls[mCPO+2][1] - tour_sites[mCTS+1][1]) < 5. &&
                        fabs(ctrls[mCPO+2][2] - tour_sites[mCTS+1][2]) < 5.)
                    {
                        fprintf(stderr,"reached site: %f %f %f\n", tour_sites[mCTS+1][0], tour_sites[mCTS+1][1], tour_sites[mCTS+1][2]);
                         mCTS--;
                         mCTSST = mCurrentTime;
                    }
            mParamT = 1.;
            mCPO-=2;
            return;
        }
        else // can't move back any more steps
        {
            mParamT = 0.;
            return;
        }
    }

    // Set Camera Position
    int fp = mCPO;
    //fprintf(stderr, "ctrl 11: %f %f %f\n", ctrls[fp+2][0], ctrls[fp+2][1], ctrls[fp+2][2]);
    //fprintf(stderr, "ctrl 01: %f %f %f\n", ctrls[fp+1][0], ctrls[fp+1][1], ctrls[fp+1][2]);
   // fprintf(stderr, "ctrl 00: %f %f %f\n", ctrls[fp][0], ctrls[fp][1], ctrls[fp][2]);

    float first = pow(t,2);
    float second = 2. * t * (1.-t);
    float third = pow((1. - t), 2);
    float x = first * ctrls[fp+2][0] + second * ctrls[fp+1][0] + third * ctrls[fp][0];
    float y = first * ctrls[fp+2][1] + second * ctrls[fp+1][1] + third * ctrls[fp][1];
    float z = first * ctrls[fp+2][2] + second * ctrls[fp+1][2] + third * ctrls[fp][2];

//put z a bit above the tour path
    z += 3.;
    //fprintf(stderr, "position: x: %f, y: %f, z: %f\n", x, y, z);
    SetCameraPosition(x,y,z);
    
    // Set Camera Orientation
    // first find the tangent: 2 (f(t,1) - f(t,0)). We can ignore the 2.
    first = t;
    second = 1. - t;
    x = (first * ctrls[fp+2][0] + second * ctrls[fp+1][0]) -
            (first * ctrls[fp+1][0] + second * ctrls[fp][0]);
    y = (first * ctrls[fp+2][1] + second * ctrls[fp+1][1]) -
            (first * ctrls[fp+1][1] + second * ctrls[fp][1]);
    z = (first * ctrls[fp+2][2] + second * ctrls[fp+1][2]) -
            (first * ctrls[fp+1][2] + second * ctrls[fp][2]);

    

    //fprintf(stderr, "tangent: %f %f %f", x,y,z);
    float yaw = atan(-1.*x/y);
    //float yaw = atan(-1.*tours[mCTS][2]/tours[mCTS][3]);
    yaw = yaw*180/PI;
    if (y < 0.)
        yaw -=180.;
    float pitch = atan(z/sqrt(pow(x,2) + pow(y,2)));
    pitch = pitch*180/PI;
    //fprintf(stderr, "pitch: %f yaw: %f\n", pitch, yaw);
    //float pitch = atan(tours[mCTS][4]/sqrt(pow(tours[mCTS][2],2) + pow(tours[mCTS][3],2)));
    SetCameraAngle(pitch,yaw);

}

void Sculpture::PrintEdge(vector<int> edge)
{
    fprintf(stderr, "Vertex 1: %d %d %d, vertex 2: %d %d %d\n", sites[edge[0]][0],sites[edge[0]][1], sites[edge[0]][2], sites[edge[1]][0],sites[edge[1]][1], sites[edge[1]][2]); 
}

void Sculpture::RenderMap()
{
    glColor3f(1.,1.,1.);
    /*glBegin(GL_LINES);
    float percent = 0.f;
    for (int i = 0; i < edges.size(); i++)
    {
        vector<int> edge = edges[i];
        //PrintEdge(edge);
        percent = (sites[edge[0]][2]+2.)/1284.;
        //fprintf(stderr, "percent: %f ", percent);
        glColor3f(percent,1.-percent,0.);
        glVertex3i(sites[edge[0]][0],sites[edge[0]][1], sites[edge[0]][2]);
        percent = (sites[edge[1]][2]+2.)/1284.;
        //fprintf(stderr, "%f\n", percent);
        glColor3f(percent,1.-percent,0.);
        glVertex3i(sites[edge[1]][0],sites[edge[1]][1], sites[edge[1]][2]);
    }
    //glVertex3i(0,0,0);
    //glVertex3i(1,1,0);
    glEnd();*/
	vector<int>triangle;
	int x,y,z;
	
	for (int i = 0; i < triangles.size(); i++)
	{
	    glColor3f(1.,1.,1.);
		triangle = triangles[i];
		//fprintf(stderr ,"triangle: %d %d %d\n", triangle[0], triangle[1], triangle[2]);
		glBegin(GL_TRIANGLES);

                //fprintf(stderr,"triangle[0]: %d ",triangle[0]);
		setColor(sites[triangle[0]][2]);
		glVertex3i(sites[triangle[0]][0], sites[triangle[0]][1], sites[triangle[0]][2]);

		setColor(sites[triangle[1]][2]);
		glVertex3i(sites[triangle[1]][0], sites[triangle[1]][1], sites[triangle[1]][2]);
		setColor(sites[triangle[2]][2]);
		glVertex3i(sites[triangle[2]][0], sites[triangle[2]][1], sites[triangle[2]][2]);
		glEnd();

		glColor3f(0.,0.,0.);
        if (glutGetWindow() == mWin2)
        {
		glBegin(GL_LINES);
		glVertex3i(sites[triangle[0]][0], sites[triangle[0]][1], sites[triangle[0]][2]);
		glVertex3i(sites[triangle[1]][0], sites[triangle[1]][1], sites[triangle[1]][2]);

		glVertex3i(sites[triangle[0]][0], sites[triangle[0]][1], sites[triangle[0]][2]);
	    glVertex3i(sites[triangle[2]][0], sites[triangle[2]][1], sites[triangle[2]][2]);

		glVertex3i(sites[triangle[1]][0], sites[triangle[1]][1], sites[triangle[1]][2]);
		glVertex3i(sites[triangle[2]][0], sites[triangle[2]][1], sites[triangle[2]][2]);
		glEnd();
        }
	}
}

void Sculpture::RenderPath()
{
    float first;
    float second;
    float third;
    float x;
    float y;
    float z;
    float tanx, tany, tanz;

    int increments = 20;
    int rinc = 10;
    float t = 0.f;
    float b;
    glColor3f(1.,0.,0.);

    int fp = 0;
    for (int b = 0; b < ctrls.size() - 2; b += 2) {
        fp = b;
        glBegin( GL_LINE_STRIP);
        for (int a = 0; a < increments + 1; a++) {
            t = ((float) a) / increments;
            first = pow(t, 2);
            second = 2. * t * (1. - t);
            third = pow((1. - t), 2);
            x = first * ctrls[fp + 2][0] + second * ctrls[fp + 1][0] + third
                    * ctrls[fp][0];
            y = first * ctrls[fp + 2][1] + second * ctrls[fp + 1][1] + third
                    * ctrls[fp][1];
            z = first * ctrls[fp + 2][2] + second * ctrls[fp + 1][2] + third
                    * ctrls[fp][2];
            //fprintf(stderr, "coordinates: %f %f %f\n", x, y, z);
            glVertex3f(x, y, z);
        }
        glEnd();

    if (mRingRadius < 0.)
        continue;
    //Now draw little rings
    for (int a = 0; a < rinc; a++)
        {
            t = ((float) a)/rinc;
            first = pow(t,2);
            second = 2. * t * (1.-t);
            third = pow((1. - t), 2);
            x = first * ctrls[fp+2][0] + second * ctrls[fp+1][0] + third * ctrls[fp][0];
            y = first * ctrls[fp+2][1] + second * ctrls[fp+1][1] + third * ctrls[fp][1];
            z = first * ctrls[fp+2][2] + second * ctrls[fp+1][2] + third * ctrls[fp][2];
            //fprintf(stderr, "coordinates: %f %f %f\n", x, y, z);
            tanx = (first * ctrls[fp+2][0] + second * ctrls[fp+1][0]) -
                    (first * ctrls[fp+1][0] + second * ctrls[fp][0]);
            tany = (first * ctrls[fp+2][1] + second * ctrls[fp+1][1]) -
                    (first * ctrls[fp+1][1] + second * ctrls[fp][1]);
            tanz = (first * ctrls[fp+2][2] + second * ctrls[fp+1][2]) -
                    (first * ctrls[fp+1][2] + second * ctrls[fp][2]);
            vector<float> ntan = normalize(tanx, tany, tanz);
            vector<float> pos(3);
            pos[0] = x;
            pos[1] = y;
            pos[2] = z;
            renderRing(pos, ntan, mRingRadius);
        }
    }

    /*GLfloat knots[6] = {0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f };
    vector<float> zz, oo, zo;
    for (int a = 0; a < ctrls.size() - 2; a += 2)
    {
    zz = ctrls[a];
    oo = ctrls[a+2];
    zo = ctrls[a+1];
    GLfloat control[3][3] =
    {{zz[0], zz[1],zz[2]},
     {zo[0],zo[1],zz[2]},
     {oo[0], oo[1], oo[2]}};

    glColor3f(1.,0.,0.);
    gluBeginCurve(mCurve);
    gluNurbsCurve(mCurve,6, knots, 3, &control[0][0], 3, GL_MAP1_VERTEX_3);
    gluEndCurve(mCurve);
   }*/
    //gluNurbsSurface(theNurb,6,knots,6,knots,3*4,4,control,3,3,GL_MAP2_VERTEX_4);
}

void Sculpture::RenderSites()
{
    for (int a = 0; a < tour_sites.size(); a++)
    {
        glPushMatrix();
        if (a <= mCTS)
            glColor3f(1.,1.,0.);
        else
            glColor3f(1.,0.,0.);
        //glTranslatef(tour_sites[a][0], tour_sites[a][1], tour_sites[a][2]);
        if (glutGetWindow() == mWin1)
        {
            glTranslatef(tour_sites[a][0], tour_sites[a][1], tour_sites[a][2]+ RADIUS);
       
            gluSphere(mQuadric, RADIUS,20,20);
        }
        else
        {
            glTranslatef(tour_sites[a][0], tour_sites[a][1], tour_sites[a][2]);
            gluSphere(mQuadric, 400, 20,20);
        }
        glPopMatrix();
    }
}

void Sculpture::RenderMe()
{
    glPushMatrix();
    glColor3f(0.8,0.25,1.);
    //glTranslatef(mCamTrans[0],mCamTrans[1],mCamTrans[2]);
    if (glutGetWindow() == mWin1)
    {
            glTranslatef(mCamTrans[0],mCamTrans[1],mCamTrans[2]+RADIUS);
            gluSphere(mQuadric, RADIUS,20,20);
    }
    else
    {
            glTranslatef(mCamTrans[0],mCamTrans[1],mCamTrans[2]);
            gluSphere(mQuadric, 400, 20,20);
    }
    glPopMatrix();
}

/**
 * Draw your sculpture here
 */
void Sculpture::Draw()
{
    glPushMatrix();

    //
    // Rotate the entire scene, so that the local Z axis points up.
    //
    glRotatef(-90.0f, 1, 0, 0);
    //
    // Because the OpenGL camera is at the origin, we must transform
    // the whole scene by the inverse of the camera transformation.
    //
    
    if (mFPP)
    {
    vector<float> iCamTrans(3);
    iCamTrans[0] = -1.*mCamTrans[0];
    iCamTrans[1] = -1.*mCamTrans[1];
    iCamTrans[2] = -1.*mCamTrans[2];

    glTranslatef(iCamTrans[0], iCamTrans[1], iCamTrans[2]);

//    glRotatef(-mCameraElevation, 1, 0, 0);
//    glRotatef(-mCameraAzimuth, 0, 1, 0);
   //Let's try this out.
   
   float rYaw = mYaw*PI/180.;
   glTranslatef(-1.*iCamTrans[0], -1.*iCamTrans[1], -1.*iCamTrans[2]);
   glRotatef(-1.*mYaw , 0,0,1);
   glRotatef(-1.*mPitch, cos(rYaw), sin(rYaw),  0);
   glTranslatef(iCamTrans[0], iCamTrans[1], iCamTrans[2]);
    }
    else
    {
        float px = -13000.;
        float py = 10000.;
        float pz = 1500.;
        
        vector<float> iCamTrans(3);
     iCamTrans[0] = -1.*(px);
     iCamTrans[1] = -1.*(py);
     iCamTrans[2] = -1.*(pz);

     glTranslatef(iCamTrans[0], iCamTrans[1], iCamTrans[2]);

 // Set Camera Orientation
    // first find the tangent: 2 (f(t,1) - f(t,0)). We can ignore the 2.
    //first = t;
    //second = 1. - t;
    
    //if (mCamInterval <= CAM_INTERVAL)
    //{
        float x,y,z;
    x = mCamTrans[0] - px; 
    y = mCamTrans[1] - py;
    z = mCamTrans[2] - pz;

    //fprintf(stderr, "tangent: %f %f %f", x,y,z);
    float sYaw = atan(-1.*x/y);
    //float yaw = atan(-1.*tours[mCTS][2]/tours[mCTS][3]);
    sYaw = sYaw*180/PI;
    if (y < 0.)
        sYaw -=180.;
    float sPitch = atan(z/sqrt(pow(x,2) + pow(y,2)));
    sPitch = sPitch*180./PI;
    mOYaw = sYaw;
    mOPitch = sPitch;
    //}
   // else 
   // {
    //    if (mCamInterval >= 2*CAM_INTERVAL) mCamInterval = 0;
   // }
    //mCamInterval++;
    // float sYaw = -110.;
     //float sPitch = 15.;
 //    glRotatef(-mCameraElevation, 1, 0, 0);
 //    glRotatef(-mCameraAzimuth, 0, 1, 0);
    //Let's try this out.
    float rYaw = mOYaw*PI/180.;
    glTranslatef(-1.*iCamTrans[0], -1.*iCamTrans[1], -1.*iCamTrans[2]);
    glRotatef(-1.*mOYaw , 0,0,1);
    glRotatef(-1.*mOPitch, cos(rYaw), sin(rYaw),  0);
    glTranslatef(iCamTrans[0], iCamTrans[1], iCamTrans[2]);
    }
    
   // Render the map
    RenderMap();
    // Render the path
    //RenderPath();
    if(!mFPP)
    {
        RenderMe();
        RenderSites();
    }    
    glPopMatrix();

}

void Sculpture::DrawSecondary()
{
    glPushMatrix();
    glRotatef(-90.0f, 1, 0, 0);
     //
     // Because the OpenGL camera is at the origin, we must transform
     // the whole scene by the inverse of the camera transformation.
     //
     vector<float> iCamTrans(3);
     iCamTrans[0] = -1.*(0.);
     iCamTrans[1] = -1.*(0.);
     iCamTrans[2] = -1.*(37000);

     glTranslatef(iCamTrans[0], iCamTrans[1], iCamTrans[2]);

     float sYaw = 20.;
     float sPitch = -89.;
 //    glRotatef(-mCameraElevation, 1, 0, 0);
 //    glRotatef(-mCameraAzimuth, 0, 1, 0);
    //Let's try this out.
    float rYaw = sYaw*PI/180.;
    glTranslatef(-1.*iCamTrans[0], -1.*iCamTrans[1], -1.*iCamTrans[2]);
    glRotatef(-1.*sYaw , 0,0,1);
    glRotatef(-1.*sPitch, cos(rYaw), sin(rYaw),  0);
    glTranslatef(iCamTrans[0], iCamTrans[1], iCamTrans[2]);

    RenderMap();
    RenderPath();
    RenderSites();
    RenderMe();
    glPopMatrix();

}

/**
 * the camera
 */
void Sculpture::Setup()
{
    mFree = 0;
    mFPP = 0;
    mRingRadius = -1.;
    mCamInterval = CAM_INTERVAL;
    //glShadeModel(GL_SMOOTH);
    mCamTrans.push_back(0.f);
    mCamTrans.push_back(0.f);
    mCamTrans.push_back(0.f);
    ReadMap();    
    TourSetup();
    mDir = D_FORWARD;
    mParamT = 0.;
    fprintf(stderr, "set mQuadratic\n");
    mCurve = gluNewNurbsRenderer();
    mQuadric = gluNewQuadric();
    PrintInitialStats();
}

float Sculpture::GetControlPointOffset()
{
    return mCPO;
}

void Sculpture::SetCameraPosition(float x, float y, float z)
{
    mCamTrans[0] = x;
    mCamTrans[1] = y;
    mCamTrans[2] = z;
}

vector<float> Sculpture::GetCameraPosition()
{
    return mCamTrans;
}

void Sculpture::SetCameraAngle(float pitch, float yaw)
{
    mYaw = yaw;
    mPitch = pitch;
}

void Sculpture::AdjustCameraPosition(float x, float y, float z)
{
    //First calculate direction we are looking at, in x y z
    float rYaw = toRadians(mYaw);
    float dx = -1.*sin(rYaw);
    float dy = cos(rYaw);
    float dz = sqrt(pow(dx,2) + pow(dy,2)) * tan(toRadians(mPitch));
    vector<float> base = normalize(dx,dy,dz);
    // y is "forward", x is "right" and z is "up"
    float cx = y * base[0];
    float cy = y * base[1];
    float cz = y * base[2];

    mCamTrans[0] += cx;
    mCamTrans[1] += cy;
    mCamTrans[2] += cz;
}

void Sculpture::AdjustCameraAngle(float pitch, float yaw)
{
    mYaw += yaw;
    mPitch += pitch;
}

void Sculpture::AddTourSite(float x, float y, float z)
{
    vector <float> site(3);
    site[0] = x;
    site[1] = y;
    site[2] = z;
    tour_sites.push_back(site);
}

void Sculpture::RemoveTourSite(int index)
{
    tour_sites.erase(tour_sites.begin() + index);
}

vector<vector <float> > Sculpture::GetTourSites()
{
    return tour_sites;
}

int Sculpture::GetCurrentTourStep()
{
    return mCTS;
}

vector<vector <float> > Sculpture::GetUnvisitedTourSites()
{
    vector<vector <float> > sites;
    for (int a = mCTS+1; a < tour_sites.size(); a++)
    {
        sites.push_back(tour_sites[a]);
    }
    return sites;
}
/**
 * Color setting methods
 */
void Sculpture::SetDiffuseColor(float r, float g, float b)
{
	float diffuse[4] = { r, g, b, 1.0f };
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
}

void Sculpture::SetSpecularColor(float r, float g, float b)
{
	float specular[4] = { r, g, b, 1.0f };
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
}

